package com.csx.data.orm.jpa.batch.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

public class SqlUtil {

    private static final Map<Class<?>,String> CLAZZ_TO_INSERT_SQL_CACHE = new ConcurrentHashMap<>();

    /**
     * 根据实体类 生成该实体类插入的sql(占位符)
     * 类似 INSERT INTO table_name (id,first_name,last_name,age,city) VALUES(?,?,?,?,?);
     * @param clazz 实体类对象
     * @return 实体类对应的插入SQL
     */
    public static String generateInsertSql(Class<?> clazz) {

        if(clazz == null) {
            return null;
        }

        // 尝试从缓存中获取,缓存中存在则直接返回
        String insertSql = CLAZZ_TO_INSERT_SQL_CACHE.get(clazz);
        if(StrUtil.isNotBlank(insertSql)) {
            return insertSql;
        }

        String tableName = TableEntityReflectUtil.getTableName(clazz);
        List<String> columns = TableEntityReflectUtil.getColumns(clazz);

        // 拼接 insert sql
        StringBuilder insertSqlBuilder = new StringBuilder("INSERT INTO ");
        insertSqlBuilder.append(tableName);
        insertSqlBuilder.append(" (");

        // join columns
        for (int i = 0; i < columns.size(); i++) {
            insertSqlBuilder.append(columns.get(i));
            if(columns.size() - 1 > i) {
                insertSqlBuilder.append(",");
            }
        }

        // join values placeholder
        insertSqlBuilder.append(") VALUES").append(" (");
        for (int i = 0; i < columns.size(); i++) {
            insertSqlBuilder.append("?");
            if(columns.size() - 1 > i) {
                insertSqlBuilder.append(",");
            }
        }

        insertSqlBuilder.append(" )");
        insertSql = insertSqlBuilder.toString();


        // cache insert sql
        CLAZZ_TO_INSERT_SQL_CACHE.put(clazz, insertSql);

        return insertSql;
    }

    /**
     * 根据实体列表生成 插入的参数列表
     * @param entities 实体列表
     * @param idGenerator ID生成器
     * @return 插入数据的参数列表
     */
    public static List<Object[]> generateInsertArgsList(List<?> entities, Supplier<Object> idGenerator) {

        if(CollectionUtil.isEmpty(entities)) {
            return new ArrayList<>();
        }

        List<Object[]> argsList = new ArrayList<>();
        String idColumn = TableEntityReflectUtil.getId(entities.get(0).getClass());
        List<String> columns = TableEntityReflectUtil.getColumns(entities.get(0).getClass());

        for (Object entity : entities) {

            Object[] args = new Object[columns.size()];

            for (int i = 0; i < columns.size(); i++) {
                if(columns.get(i).equals(idColumn)) {
                    if(idGenerator != null) {
                        Object id = idGenerator.get();
                        args[i] = id;
                    } else {
                        args[i] = TableEntityReflectUtil.getColumnValue(columns.get(i), entity);
                    }
                } else {
                    args[i] = TableEntityReflectUtil.getColumnValue(columns.get(i), entity);
                }
            }

            argsList.add(args);
        }

        return argsList;
    }


}
